﻿ /*------------------------------------------------------------------
-- COPYRIGHT (C) 2010-2012  Atom
-- ALL RIGHTS RESERVED.
-- 兆尹科技
-- CREATE DATE: 2010/07/12
-- CREATE MAN:liujian	
-- DAL中的所有数据访问类，都需要继承BaseDAL 类
-- MODIFY HISTORY:
-- MODIFY DATE:
-- MODIFY MAN:	
-- MODIFY DESC:
-- MODIFY DATE:
-- MODIFY MAN:	
-- MODIFY DESC:
---------------------------------------------------------------------*/

#region Namespace
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Data.Common;
using System.Reflection;
using Atom.Utility;
using Atom.Utility.Data;
using Atom.Common;
using Atom.Entity; 
#endregion

namespace Atom.DAL
{
    /// <summary>
    /// 创建Database委托
    /// </summary>
    /// <returns>数据访问工具类实例</returns>
    public delegate Database CreateDataBaseHandler();

    /// <summary>
    /// DAL所有数据访问类的基类
    /// </summary>
    /// <remarks>DAL中的所有数据访问类，都需要继承BaseDAL</remarks>
    public class BaseDAL : BaseDataUtility
    {
        #region 初始化
        private Database db;
        private string databaseName;

        /// <summary>
        /// 默认的数据库连接字符串在配置文件的名称
        /// </summary>
        internal static readonly string DEFALUT_DATABASE_NAME = "DefaultConnection";
        /// <summary>
        /// 默认根据属性名获取属性对象的策略。
        /// </summary>
        private static BindingFlags PublicInstancePropertyBindingFlags = BindingFlags.CreateInstance
            | BindingFlags.Instance         //实例
            | BindingFlags.Public           //公有
            | BindingFlags.SetProperty      //可写属性
            | BindingFlags.IgnoreCase;      //忽略大小写

        /// <summary>
        /// 构造函数
        /// </summary>
        public BaseDAL()
            : this(DEFALUT_DATABASE_NAME)
        {
        }

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="databaseName">数据库连接字符串在配置文件的名称</param>
        internal BaseDAL(string databaseName)
        {
            this.databaseName = databaseName;
        }

        /// <summary>
        /// 创建Database对象
        /// </summary>
        /// <returns>数据访问工具类实例</returns>
        protected override Database CreateDataBase()
        {
            if (db == null)
            {
                db = CreateDataAccess(databaseName);
            }
            return db;
        }

        /// <summary>
        /// 获取Database对象
        /// </summary>
        public Database Database
        {
            get 
            {
                return CreateDataBase();
            }
        }
        #endregion

        #region DataAccess
        /// <summary>
        /// 数据库执行工具类
        /// </summary>
        internal protected new Database DataAccess
        {
            get
            {
                return base.DataAccess;
            }
        } 
        #endregion

        #region ExecuteInsertWithGetIdentity
        /// <summary>
        /// 执行Insert语句，并且输出新增的自增长值
        /// </summary>
        /// <param name="cmd">Sql命令</param>
        /// <param name="trans">事务对象，如果为null，则不使用事务</param>
        /// <param name="id">如果执行Insert语句成功，则输出自增长值；否则输出0.</param>
        /// <returns>执行结果，参考<see cref="Atom.Entity.SqlExecuteResult"/></returns>
        /// <remarks>如果参数trans不为null的话：调用此方法的过程中，trans是不会做Commit，必须方法外部做Commit；但如果出现异常，trans会执行Rollback。</remarks>
        internal SqlExecuteResult ExecuteInsertWithGetIdentity(DbCommand cmd, DbTransaction trans, out int id)
        {
            SqlExecuteResult result = new SqlExecuteResult();
            id = default(int);

            //在Insert语句后面添加获取自增长Id的语句
            cmd.CommandText += ";" + CommonUseSqlFormat.RETRIEVE_NEWID;

            if (trans == null)
            {
                try
                {
                    object newid = DataAccess.ExecuteScalar(cmd);
                    if (!IsNullValue(newid))
                    {
                        id = Convert.ToInt32(newid);
                        result.Success = true;
                    }
                }
                catch (Exception ex)
                {
                    result.Success = false;
                    result.Exception = ex;
                }
            }
            else
            {
                try
                {
                    object newid = DataAccess.ExecuteScalar(cmd, trans);
                    if (!IsNullValue(newid))
                    {
                        id = Convert.ToInt32(newid);
                        result.Success = true;
                    }
                }
                catch (Exception ex)
                {
                    result.Success = false;
                    result.Exception = ex;
                    DAOManager.RollbackTransaction(trans);
                }
            }

            return result;
        } 
        #endregion

        #region ExecuteCommand
        /// <summary>
        /// 在事务中，执行Sql命令。
        /// </summary>
        /// <param name="command">Sql命令</param>
        /// <param name="trans">事务对象，如果为null，则不使用事务</param>
        /// <returns>执行结果，参考<see cref="Atom.Entity.SqlExecuteResult"/></returns>
        /// <remarks>如果参数trans不为null的话：调用此方法的过程中，trans是不会做Commit，必须方法外部做Commit；但如果出现异常，trans会执行Rollback。</remarks>
        internal SqlExecuteResult ExecuteCommand(DbCommand command, DbTransaction trans)
        {
            return ExecuteCommands(new List<DbCommand>() { command }, trans);
        } 
        #endregion

        #region ExecuteCommands
        /// <summary>
        /// 在事务中，执行一组Sql命令。
        /// </summary>
        /// <param name="commands">Sql命令列表</param>
        /// <param name="trans">事务对象，如果为null，则不使用事务</param>
        /// <returns>执行结果，参考<see cref="Atom.Entity.SqlExecuteResult"/></returns>
        /// <remarks>如果参数trans不为null的话：调用此方法的过程中，trans是不会做Commit，必须方法外部做Commit；但如果出现异常，trans会执行Rollback。</remarks>
        internal SqlExecuteResult ExecuteCommands(List<DbCommand> commands, DbTransaction trans)
        {
            SqlExecuteResult result = new SqlExecuteResult();

            if (trans == null)
            {
                //自己创建一个事务执行
                return DAOManager.ExecuteTransaction(this.Database, _trans => 
                {
                    try
                    {
                        foreach (var command in commands)
                        {
                            DataAccess.ExecuteNonQuery(command, _trans);
                        }
                        result.Success = true;
                    }
                    catch (Exception ex)
                    {
                        result.Success = false;
                        result.Exception = ex;
                        DAOManager.RollbackTransaction(_trans);
                    }
                    return result;
                });                
            }
            else
            {
                try
                {
                    foreach (var command in commands)
                    {
                        DataAccess.ExecuteNonQuery(command, trans);
                    }
                    result.Success = true;
                }
                catch (Exception ex)
                {
                    result.Success = false;
                    result.Exception = ex;
                    DAOManager.RollbackTransaction(trans);
                }
            }

            return result;
        } 
        #endregion

        #region CheckExist
        /// <summary>
        /// 检查数据是否在数据库中才能在
        /// </summary>
        /// <param name="tableName">表名称</param>
        /// <param name="columnName">栏位名</param>
        /// <param name="mapperValue">比对的值</param>
        /// <param name="idColumnName">PK的栏位</param>
        /// <param name="trans">事务</param>
        /// <param name="result">输出结果，参考<see cref="Atom.Entity.SqlExecuteResult"/>。如果数据存在，SqlExecuteResult的TokenObject包含了此笔数据的Id值；Exception抛出的异常类型为CheckExistException</param>
        /// <returns>true，表示数据已存在；false，相关数据不存在。</returns>
        internal bool CheckExist(string tableName, string columnName, string mapperValue
            , string idColumnName, DbTransaction trans
            , out SqlExecuteResult result)
        {
            bool isExist = false;
            result = null;

            /*
             * 组合执行以下Sql
             * select {idColumnName} from {tableName} where {columnName} = {mapperValue}
             */
            string sql = string.Format("SELECT {2} FROM {0} WHERE {1} = @val "
                , tableName, columnName, idColumnName);

            DbCommand cmd = DataAccess.GetSqlStringCommand(sql);

            DataAccess.AddInParameter(cmd, "val", DbType.String, mapperValue);

            using (IDataReader dr = (trans == null ? DataAccess.ExecuteReader(cmd) : DataAccess.ExecuteReader(cmd, trans)))
            {
                if (dr.Read())
                {
                    isExist = true;
                    result = new SqlExecuteResult()
                    {
                        Success = false,
                        //检测记录是否存在的异常
                        Exception = new CheckExistException() 
                        {
                            Mark = columnName.ToLower()
                        },
                        TokenObject = dr[idColumnName],
                    };
                }
            }

            return isExist;
        } 
        #endregion

        #region SetCommandValue

        #region CommandMapper
        /// <summary>
        /// 字段名称映射
        /// </summary>
        internal class CommandMapper
        {
            /// <summary>
            /// 构造函数
            /// </summary>
            /// <param name="colName">字段名称（参数名与字段名一样、属性名为字段名去掉下划线）</param>
            internal CommandMapper(string colName)
                : this(colName, colName, GetPropertyNameByColumnName(colName))
            {
            }

            /// <summary>
            /// 构造函数
            /// </summary>
            /// <param name="colName">字段名称</param>
            /// <param name="parameterName">参数名称</param>
            /// <param name="propertyName">属性名称</param>
            internal CommandMapper(string colName, string parameterName, string propertyName)
            {
                this.ColumnName = colName;
                this.ParameterName = parameterName;
                this.PropertyName = propertyName;
            }

            /// <summary>
            /// 字段名称
            /// </summary>
            internal string ColumnName { get; private set; }
            /// <summary>
            /// 参数名称
            /// </summary>
            internal string ParameterName { get; private set; }
            /// <summary>
            /// 属性名称
            /// </summary>
            internal string PropertyName { get; private set; }
        } 
        #endregion

        #region SetCommandValueWithCheck
        /// <summary>
        /// 为DbCommand赋值参数，赋值时添加检测（只检测字符串大小是否大于数据库所设长度）
        /// </summary>
        /// <param name="entity">实体</param>
        /// <param name="mappers">字段、属性、参数名称的映射关系</param>
        /// <param name="cmd">Command对象</param>
        /// <param name="tableName">Command要设置的相关表名</param>
        /// <returns>错误参数信息，如果没错误返回空集合</returns>
        internal List<CheckInvalidValue> SetCommandValueWithCheck(object entity
            , List<CommandMapper> mappers
            , DbCommand cmd, string tableName)
        {
            List<CheckInvalidValue> list = new List<CheckInvalidValue>();
            Type entityType = entity.GetType();

            foreach (var mapper in mappers)
            {
                PropertyInfo pInfo = entityType.GetProperty(mapper.PropertyName, PublicInstancePropertyBindingFlags);
                if (pInfo == null) throw new Exception(entityType.FullName + "类型不存在" + mapper.PropertyName + "属性");

                Type pType = pInfo.PropertyType;
                if (pType == typeof(string))
                {
                    //字符串才检验
                    var checkInvalid = SetCommandValueWithCheck(entity
                        , pInfo
                        , mapper.ParameterName
                        , cmd
                        , mapper.ColumnName
                        , tableName);
                    if (checkInvalid != null)
                    {
                        list.Add(checkInvalid);
                    }
                }
                else
                {
                    if (CollectionUti.HasItem(list))
                    {
                        continue;
                    }
                    else
                    {
                        this.SetCommandValue(entity, pInfo, mapper.ParameterName, cmd);
                    }
                }
            }

            return list;
        }

        /// <summary>
        /// 为DbCommand赋值参数，赋值时添加检测（只检测字符串大小是否大于数据库所设长度）
        /// </summary>
        /// <param name="entity">相关实体</param>
        /// <param name="propertyName">属性名称</param>
        /// <param name="parameterName">要复制的采纳数</param>
        /// <param name="cmd">DbCommand命令</param>
        /// <param name="mapperColName">字段名</param>
        /// <param name="tableName">表名</param>
        /// <returns></returns>
        internal CheckInvalidValue SetCommandValueWithCheck(object entity, string propertyName
            , string parameterName, DbCommand cmd
            , string mapperColName, string tableName)
        {
            Type entityType = entity.GetType();

            PropertyInfo pInfo = entityType.GetProperty(propertyName, PublicInstancePropertyBindingFlags);
            if (pInfo == null) throw new Exception(entityType.FullName + "类型不存在" + propertyName + "属性");

            return SetCommandValueWithCheck(entity
                , pInfo
                , parameterName
                , cmd
                , mapperColName
                , tableName);
        }

        /// <summary>
        /// 为DbCommand赋值参数，赋值时添加检测（只检测字符串大小是否大于数据库所设长度）
        /// </summary>
        /// <param name="entity">相关实体</param>
        /// <param name="pInfo">属性名称</param>
        /// <param name="parameterName">要复制的采纳数</param>
        /// <param name="cmd">DbCommand命令</param>
        /// <param name="mapperColName">字段名</param>
        /// <param name="tableName">表名</param>
        /// <returns></returns>
        internal CheckInvalidValue SetCommandValueWithCheck(object entity, PropertyInfo pInfo
            , string parameterName, DbCommand cmd
            , string mapperColName, string tableName)
        {
            object val = pInfo.GetValue(entity, null);
            CheckInvalidValue checkInvalidValue = null;

            mapperColName = mapperColName.ToUpper();

            var schema = DAOManager.LoadTableSchema(tableName, this.DataAccess);
            if (!schema.ContainsKey(mapperColName))
            {
                throw new Exception(mapperColName + "在表" + tableName + "中不存在");
            }
            DatabaseColumnStruct dbColumnStruct = schema[mapperColName];
            //字符串才检查
            if (dbColumnStruct.DbType == typeof(string))
            {
                if (!dbColumnStruct.AllowDBNull && (val == null || val.ToString() == ""))
                {
                    //检查为null不合法
                    checkInvalidValue = new CheckInvalidValue()
                    {
                        DBColumnStruct = dbColumnStruct,
                        EntityType = entity.GetType(),
                        PropertyName = pInfo.Name,
                        Value = val,
                        InvalidMessage = "不允许为空"
                    };
                }

                if (checkInvalidValue == null && val != null)
                {
                    //检查长度
                    string valString = val.ToString();
                    if (valString.Length > dbColumnStruct.Size)
                    {
                        checkInvalidValue = new CheckInvalidValue()
                        {
                            DBColumnStruct = dbColumnStruct,
                            EntityType = entity.GetType(),
                            PropertyName = pInfo.Name,
                            Value = val,
                            InvalidMessage = "超过数据库预设长度" + dbColumnStruct.Size.ToString()
                        };
                    }
                }
            }

            if (checkInvalidValue == null)
            {
                //为DbCommand赋值
                DataAccess.AddInParameter(cmd, parameterName, DbType.String, val ?? (object)DBNull.Value);
            }

            return checkInvalidValue;
        }

        /// <summary>
        /// 为DbCommand赋值参数，赋值时添加检测（只检测字符串大小是否大于数据库所设长度）
        /// </summary>
        /// <param name="val">值</param>
        /// <param name="parameterName">参数名称</param>
        /// <param name="cmd">Command对象</param>
        /// <param name="mapperColName">对应的字段名称</param>
        /// <param name="tableName">Command要设置的相关表名</param>
        /// <returns>错误参数信息，如果没错误返回null</returns>
        internal CheckInvalidValue SetCommandValueWithCheck(object val, string parameterName
            , DbCommand cmd
            , string mapperColName
            , string tableName)
        {
            CheckInvalidValue checkInvalidValue = null;

            mapperColName = mapperColName.ToUpper();

            var schema = DAOManager.LoadTableSchema(tableName, this.DataAccess);
            if (!schema.ContainsKey(mapperColName))
            {
                throw new Exception(mapperColName + "在表" + tableName + "中不存在");
            }
            DatabaseColumnStruct dbColumnStruct = schema[mapperColName];
            //字符串才检查
            if (dbColumnStruct.DbType == typeof(string))
            {
                if (!dbColumnStruct.AllowDBNull && (val == null || val.ToString() == ""))
                {
                    //检查为null不合法
                    checkInvalidValue = new CheckInvalidValue()
                    {
                        DBColumnStruct = dbColumnStruct,
                        EntityType = null,
                        PropertyName = null,
                        Value = val,
                        InvalidMessage = "不允许为空"
                    };
                }

                if (checkInvalidValue == null && val != null)
                {
                    //检查长度
                    string valString = val.ToString();
                    if (valString.Length > dbColumnStruct.Size)
                    {
                        checkInvalidValue = new CheckInvalidValue()
                        {
                            DBColumnStruct = dbColumnStruct,
                            EntityType = null,
                            PropertyName = null,
                            Value = val,
                            InvalidMessage = "超过数据库预设长度" + dbColumnStruct.Size.ToString()
                        };
                    }
                }
            }

            if (checkInvalidValue == null)
            {
                //为DbCommand赋值
                DataAccess.AddInParameter(cmd, parameterName, DbType.String, val ?? (object)DBNull.Value);
            }

            return checkInvalidValue;
        }         
        #endregion

        #region SetCommandValue
        /// <summary>
        /// 为DbCommand赋值参数
        /// </summary>
        /// <param name="entity">实体</param>
        /// <param name="propName">实体的属性名</param>
        /// <param name="parameterName">参数名</param>
        /// <param name="cmd">DbCommand对象</param>
        internal void SetCommandValue(object entity, string propName, string parameterName, DbCommand cmd)
        {
            PropertyInfo pInfo = entity.GetType().GetProperty(propName);
            SetCommandValue(entity, pInfo, parameterName, cmd);
        }

        /// <summary>
        /// 为DbCommand赋值参数
        /// </summary>
        /// <param name="entity">实体</param>
        /// <param name="pInfo">实体的属性</param>
        /// <param name="parameterName">参数名</param>
        /// <param name="cmd">DbCommand对象</param>
        private void SetCommandValue(object entity, PropertyInfo pInfo, string parameterName, DbCommand cmd)
        {
            Type type = pInfo.PropertyType;

            object val = pInfo.GetValue(entity, null);

            if (type.IsEnum)
            {
                val = (int)val;
                type = typeof(int);
            }

            if (type == typeof(int))
            {
                DataAccess.AddInParameter(cmd, parameterName, DbType.Int32, val);
            }
            else if (type == typeof(decimal))
            {
                DataAccess.AddInParameter(cmd, parameterName, DbType.Decimal, val);
            }
            else if (type == typeof(DateTime))
            {
                DataAccess.AddInParameter(cmd, parameterName, DbType.DateTime, val);
            }
            else if (type == typeof(double))
            {
                DataAccess.AddInParameter(cmd, parameterName, DbType.Double, val);
            }
            else if (type == typeof(long))
            {
                DataAccess.AddInParameter(cmd, parameterName, DbType.Int64, val);
            }
            else if (type == typeof(int?))
            {
                DataAccess.AddInParameter(cmd, parameterName, DbType.Int32, GetNullableDbValue<int>((int?)val));
            }
            else if (type == typeof(decimal?))
            {
                DataAccess.AddInParameter(cmd, parameterName, DbType.Decimal, GetNullableDbValue<decimal>((decimal?)val));
            }
            else if (type == typeof(DateTime?))
            {
                DataAccess.AddInParameter(cmd, parameterName, DbType.DateTime, GetNullableDbValue<DateTime>((DateTime?)val));
            }
            else if (type == typeof(double?))
            {
                DataAccess.AddInParameter(cmd, parameterName, DbType.Double, GetNullableDbValue<double>((double?)val));
            }
            else if (type == typeof(long?))
            {
                DataAccess.AddInParameter(cmd, parameterName, DbType.Int64, GetNullableDbValue<long>((long?)val));
            }
            else
            {
                DataAccess.AddInParameter(cmd, parameterName, DbType.String, val);
            }
        } 
        #endregion

        #endregion

        #region GetPropertyNameByColumnName
        /// <summary>
        /// 根据字段名称，寻找属性名称的默认规则
        /// </summary>
        /// <param name="colName">字段名称</param>
        /// <returns>返回实体属性名称</returns>
        internal static string GetPropertyNameByColumnName(string colName)
        {
            return colName.Replace("_", "");
        } 
        #endregion

        #region SetEntityUti
        /// <summary>
        /// 创建SetEntity的委托
        /// </summary>
        /// <typeparam name="T">实体的类型</typeparam>
        /// <returns></returns>
        internal Action<T, IDataReader> CreateSetEntityHandler<T>()
            where T : BaseEntity
        {
             return new Action<T, IDataReader>((_entity, _reader) =>
             {
                 SetEntityUti(_entity, _reader);
             });
        }

        /// <summary>
        /// 从DataReader获取数据到实体
        /// </summary>
        /// <param name="entity">实体，不允许为空</param>
        /// <param name="dr">DataReader对象，不允许为空</param>
        internal void SetEntityUti(object entity, IDataReader dr)
        {
            this.SetEntityUti(entity, dr, delegate
            {
                return true;
            });
        }

        /// <summary>
        /// 从DataReader获取数据到实体
        /// </summary>
        /// <param name="entity">实体，不允许为空</param>
        /// <param name="dr">DataReader对象，不允许为空</param>
        /// <param name="mapper">属性与字段名称的映射，Key：为字段名，必须都为大写；Value为属性名</param>
        internal void SetEntityUti(object entity, IDataReader dr, Dictionary<string, string> mapper)
        {
            SetEntityUti(entity, dr, (_pInfo, _colName) => 
            {
                if (mapper.ContainsKey(_colName.ToUpper()))
                {
                    SetEntityUti(entity, mapper[_colName.ToUpper()], _colName, dr);
                    return false;
                }
                return true;
            });
        }

        /// <summary>
        /// 从DataReader获取数据到实体
        /// </summary>
        /// <param name="entity">实体，不允许为空</param>
        /// <param name="dr">DataReader对象，不允许为空</param>
        /// <param name="action">特殊处理，返回true时，就函数默认处理；返回false，函数就不处理</param>
        internal void SetEntityUti(object entity, IDataReader dr, Func<PropertyInfo, string, bool> action)
        {
            Type entityType = entity.GetType();
            //循环dr的所有字段
            int fieldCount = dr.FieldCount;
            for (int fieldIndex = 0; fieldIndex < fieldCount; fieldIndex++)
            {
                //根据字段名称转换为属性名
                string colName = dr.GetName(fieldIndex);
                string propertyName = GetPropertyNameByColumnName(colName);
                PropertyInfo pInfo = entityType.GetProperty(propertyName, PublicInstancePropertyBindingFlags);

                if (action(pInfo, colName) && pInfo != null)
                {
                    SetEntityUti(entity, pInfo, colName, dr);
                }
            }
        }       

        /// <summary>
        /// 从DataReader获取数据到实体
        /// </summary>
        /// <param name="entity">实体，不允许为空</param>
        /// <param name="propName">属性名，不允许为空</param>
        /// <param name="colName">字段名，不允许为空</param>
        /// <param name="dr">DataReader对象，不允许为空</param>
        /// <remarks>一般不建议使用，效率问题</remarks>
        internal void SetEntityUti(object entity, string propName, string colName, IDataReader dr)
        {
            if (string.IsNullOrEmpty(propName)) throw new NullReferenceException("pInfo不允许为空");
            if (entity == null) throw new NullReferenceException("entity不允许为空");

            PropertyInfo pInfo = entity.GetType().GetProperty(propName, PublicInstancePropertyBindingFlags);
            if (pInfo == null)
            {
                throw new Exception(propName + "属性在" + entity.GetType().FullName + "不存在");
            }
            SetEntityUti(entity, pInfo, colName, dr);
        }

        /// <summary>
        /// 从DataReader获取数据到实体
        /// </summary>
        /// <param name="entity">实体，不允许为空</param>
        /// <param name="pInfo">属性对象，不允许为空</param>
        /// <param name="colName">字段名，不允许为空</param>
        /// <param name="dr">DataReader对象，不允许为空</param>
        /// <remarks>一般不建议使用，效率问题</remarks>
        internal void SetEntityUti(object entity, PropertyInfo pInfo, string colName, IDataReader dr)
        {
            if (pInfo == null) throw new NullReferenceException("pInfo不允许为空");
            if (entity == null) throw new NullReferenceException("entity不允许为空");

            Type pType = pInfo.PropertyType;

            if (pType == typeof(int))
            {
                pInfo.SetValue(entity, GetDataByDataReader<int>(dr, colName, DefaultData.INT), null);
            }
            else if (pType == typeof(int?))
            {
                pInfo.SetValue(entity, GetNullableDataByDataReader<int>(dr, colName), null); 
            } 
            else if (pType == typeof(decimal))
            {
                pInfo.SetValue(entity, GetDataByDataReader<decimal>(dr, colName, DefaultData.DECIMAL), null);
            }
            else if (pType == typeof(decimal?))
            {
                pInfo.SetValue(entity, GetNullableDataByDataReader<decimal>(dr, colName), null); 
            }
            else if (pType == typeof(Double))
            {
                pInfo.SetValue(entity, GetDataByDataReader<Double>(dr, colName, DefaultData.DOUBLE), null);
            }
            else if (pType == typeof(Double?))
            {
                pInfo.SetValue(entity, GetNullableDataByDataReader<Double>(dr, colName), null); 
            }
            else if (pType == typeof(DateTime))
            {
                pInfo.SetValue(entity, GetDataByDataReader<DateTime>(dr, colName, DefaultData.DATETIME), null);
            }
            else if (pType == typeof(DateTime?))
            {
                pInfo.SetValue(entity, GetNullableDataByDataReader<DateTime>(dr, colName), null); 
            }
            else if (pType == typeof(long))
            {
                pInfo.SetValue(entity, GetDataByDataReader<long>(dr, colName, DefaultData.LONG), null);
            } 
            else if (pType == typeof(long?))
            {
                pInfo.SetValue(entity, GetNullableDataByDataReader<long>(dr, colName), null); 
            }
            else if (pType == typeof(Boolean))
            {
                pInfo.SetValue(entity, GetDataByDataReader<Boolean>(dr, colName, DefaultData.BOOLEAN), null);
            } 
            else if (pType == typeof(Boolean?))
            {
                pInfo.SetValue(entity, GetNullableDataByDataReader<Boolean>(dr, colName), null);
            }
            else
            {
                pInfo.SetValue(entity, GetTrimString(dr, colName), null);
            }
        }
        #endregion

        #region GetNullableDbValue
		/// <summary>
        /// 把可空值的数据转成Db数据
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="val"></param>
        /// <returns></returns>
        internal static object GetNullableDbValue<T>(Nullable<T> val)
            where T : struct
        {
            if(val.HasValue)
            {
                return val.Value;
            }

            return DBNull.Value;
        } 
        #endregion

        #region 可供自定义创建Database
        /// <summary>
        /// 【提供给UnitTest使用】Be convenient for changing the ConnectionString in test.
        /// </summary>
        private static CreateDataBaseHandler createDataBaseHandler;

        /// <summary>
        /// 【提供给UnitTest使用】Change the default connection string
        /// </summary>
        /// <param name="handler"></param>
        public static void SetCreateDataBaseHandler(CreateDataBaseHandler handler)
        {
            createDataBaseHandler = handler;
        }
        #endregion

        #region CreateDataAccess
        /// <summary>
        /// 获取配置文件中的数据库字符串信息，并解密
        /// </summary>
        /// <param name="databaseName"></param>
        /// <returns></returns>
        public static Database CreateDataAccess(string databaseName)
        {
            Database database = null;
            if (createDataBaseHandler == null)
            {
                //读取Web.Config
                var config = ConfigurationManager.ConnectionStrings[databaseName];
                //config.ConnectionString = ConnectionStringCryptography.Decrypt(config.ConnectionString);

                //解密字符串
                ConnectionStringSettings csCopy = new ConnectionStringSettings();
               // csCopy.ConnectionString = ConnectionStringCryptography.Decrypt(config.ConnectionString);
                csCopy.ConnectionString = config.ConnectionString;
                csCopy.ProviderName = config.ProviderName;
                csCopy.Name = config.Name;

                

                database = DatabaseFactory.CreateDatabase(csCopy);
              
            }
            else
            {
                database = createDataBaseHandler();
            }
            return database;
        }  
        #endregion
    }
}
